<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>ThreadLocal | Oliver知识收集站</title>
    <meta name="generator" content="VuePress 1.9.7">
    
    <meta name="description" content="享受着互联网广泛知识，并加以记录，日积月累让它成为一个档案处！">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
    
    <link rel="preload" href="/oliver-vuepress/assets/css/0.styles.4ea20d86.css" as="style"><link rel="preload" href="/oliver-vuepress/assets/js/app.c21e6ffc.js" as="script"><link rel="preload" href="/oliver-vuepress/assets/js/3.6dd9a2a1.js" as="script"><link rel="preload" href="/oliver-vuepress/assets/js/1.898920d0.js" as="script"><link rel="preload" href="/oliver-vuepress/assets/js/29.50398f0f.js" as="script"><link rel="prefetch" href="/oliver-vuepress/assets/js/10.41b2bf91.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/11.a95c117d.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/12.8607f0e1.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/13.a52d6846.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/14.249b4e52.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/15.d458d12e.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/16.ba334206.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/17.1b91c9fa.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/18.e2ea2eb5.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/19.bf0e2553.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/20.268bd174.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/21.cd1bbed5.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/22.da4bc7f7.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/23.12f0c72f.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/24.b7886742.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/25.6e71af85.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/26.5c127243.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/27.e98fd8bf.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/28.ce83b09c.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/30.05e1339c.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/31.ef4b13fb.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/32.ba5f8351.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/33.3902db0a.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/34.36a05884.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/35.87215872.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/36.db360c58.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/37.402e5374.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/38.c9228dd8.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/39.72ba5d1f.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/4.7bb03d47.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/40.7e7949bf.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/41.c0d5b947.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/42.d9984467.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/43.e6a43668.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/44.10d7fe47.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/45.f692ec2d.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/46.9b920343.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/47.8e3d94f9.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/48.7d356e5b.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/49.b0df6271.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/5.1fa544da.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/50.805e1466.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/51.1b31d40e.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/52.44e69a41.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/53.da1def53.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/54.6569f7db.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/55.5fc3de47.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/56.da649377.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/57.6ff15ed4.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/58.a62f6424.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/59.f68ae517.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/6.f5bd8e9b.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/60.dda416bc.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/61.4e0c719f.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/62.8c5ef01e.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/63.7089eb8b.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/64.b5ec150d.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/65.6720cda4.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/66.4ee90e29.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/67.cc4b0c6d.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/7.d5950c53.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/8.382fb3a5.js"><link rel="prefetch" href="/oliver-vuepress/assets/js/9.d593f4c1.js">
    <link rel="stylesheet" href="/oliver-vuepress/assets/css/0.styles.4ea20d86.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container" data-v-130b300a><div data-v-130b300a><div class="password-shadow password-wrapper-out" style="display:none;" data-v-25ba6db2 data-v-130b300a data-v-130b300a><h3 class="title" data-v-25ba6db2 data-v-25ba6db2>Oliver知识收集站</h3> <p class="description" data-v-25ba6db2 data-v-25ba6db2>享受着互联网广泛知识，并加以记录，日积月累让它成为一个档案处！</p> <label id="box" class="inputBox" data-v-25ba6db2 data-v-25ba6db2><input type="password" value="" data-v-25ba6db2> <span data-v-25ba6db2>Konck! Knock!</span> <button data-v-25ba6db2>OK</button></label> <div class="footer" data-v-25ba6db2 data-v-25ba6db2><span data-v-25ba6db2><i class="iconfont reco-theme" data-v-25ba6db2></i> <a target="blank" href="https://vuepress-theme-reco.recoluan.com" data-v-25ba6db2>vuePress-theme-reco</a></span> <span data-v-25ba6db2><i class="iconfont reco-copyright" data-v-25ba6db2></i> <a data-v-25ba6db2><span data-v-25ba6db2>oliver.shi</span>
            
          <!---->
          2022
        </a></span></div></div> <div class="hide" data-v-130b300a><header class="navbar" data-v-130b300a><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/oliver-vuepress/" class="home-link router-link-active"><!----> <span class="site-name">Oliver知识收集站</span></a> <div class="links"><div class="color-picker"><a class="color-button"><i class="iconfont reco-color"></i></a> <div class="color-picker-menu" style="display:none;"><div class="mode-options"><h4 class="title">Choose mode</h4> <ul class="color-mode-options"><li class="dark">dark</li><li class="auto active">auto</li><li class="light">light</li></ul></div></div></div> <div class="search-box"><i class="iconfont reco-search"></i> <input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/oliver-vuepress/" class="nav-link"><i class="undefined"></i>
  主页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="undefined"></i>
      Java
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/java/basics/" class="nav-link"><i class="undefined"></i>
  基础
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/java/concurrent/" class="nav-link router-link-active"><i class="undefined"></i>
  并发
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/java/jvm/jvm.html" class="nav-link"><i class="undefined"></i>
  JVM
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/java/other/" class="nav-link"><i class="undefined"></i>
  杂
</a></li></ul></div></div><div class="nav-item"><a href="/oliver-vuepress/articles/spring/first.html" class="nav-link"><i class="undefined"></i>
  Spring
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="undefined"></i>
      中间件
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/middleware/redis/redis.html" class="nav-link"><i class="undefined"></i>
  Redis
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/middleware/kafka/framework.html" class="nav-link"><i class="undefined"></i>
  Kafka
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/middleware/zookeeper.html" class="nav-link"><i class="undefined"></i>
  Zookeeper
</a></li></ul></div></div><div class="nav-item"><a href="/oliver-vuepress/articles/algorithm/" class="nav-link"><i class="undefined"></i>
  算法
</a></div><div class="nav-item"><a href="/oliver-vuepress/timeline/" class="nav-link"><i class="iconfont reco-date"></i>
  TimeLine
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="undefined"></i>
      收集站
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/article/first.html" class="nav-link"><i class="undefined"></i>
  技术好文
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/book/first.html" class="nav-link"><i class="undefined"></i>
  书籍
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/assembly/first.html" class="nav-link"><i class="undefined"></i>
  优秀开发组件
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/software/first.html" class="nav-link"><i class="undefined"></i>
  软件
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/plugin/first.html" class="nav-link"><i class="undefined"></i>
  插件
</a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask" data-v-130b300a></div> <aside class="sidebar" data-v-130b300a><div class="personal-info-wrapper" data-v-39576ba9 data-v-130b300a><!----> <h3 class="name" data-v-39576ba9>
    oliver.shi
  </h3> <div class="num" data-v-39576ba9><div data-v-39576ba9><h3 data-v-39576ba9>52</h3> <h6 data-v-39576ba9>Articles</h6></div> <div data-v-39576ba9><h3 data-v-39576ba9>6</h3> <h6 data-v-39576ba9>Tags</h6></div></div> <ul class="social-links" data-v-39576ba9></ul> <hr data-v-39576ba9></div> <nav class="nav-links"><div class="nav-item"><a href="/oliver-vuepress/" class="nav-link"><i class="undefined"></i>
  主页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="undefined"></i>
      Java
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/java/basics/" class="nav-link"><i class="undefined"></i>
  基础
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/java/concurrent/" class="nav-link router-link-active"><i class="undefined"></i>
  并发
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/java/jvm/jvm.html" class="nav-link"><i class="undefined"></i>
  JVM
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/java/other/" class="nav-link"><i class="undefined"></i>
  杂
</a></li></ul></div></div><div class="nav-item"><a href="/oliver-vuepress/articles/spring/first.html" class="nav-link"><i class="undefined"></i>
  Spring
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="undefined"></i>
      中间件
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/middleware/redis/redis.html" class="nav-link"><i class="undefined"></i>
  Redis
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/middleware/kafka/framework.html" class="nav-link"><i class="undefined"></i>
  Kafka
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/middleware/zookeeper.html" class="nav-link"><i class="undefined"></i>
  Zookeeper
</a></li></ul></div></div><div class="nav-item"><a href="/oliver-vuepress/articles/algorithm/" class="nav-link"><i class="undefined"></i>
  算法
</a></div><div class="nav-item"><a href="/oliver-vuepress/timeline/" class="nav-link"><i class="iconfont reco-date"></i>
  TimeLine
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="undefined"></i>
      收集站
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/article/first.html" class="nav-link"><i class="undefined"></i>
  技术好文
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/book/first.html" class="nav-link"><i class="undefined"></i>
  书籍
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/assembly/first.html" class="nav-link"><i class="undefined"></i>
  优秀开发组件
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/software/first.html" class="nav-link"><i class="undefined"></i>
  软件
</a></li><li class="dropdown-item"><!----> <a href="/oliver-vuepress/articles/collect/plugin/first.html" class="nav-link"><i class="undefined"></i>
  插件
</a></li></ul></div></div> <!----></nav> <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>并发</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/oliver-vuepress/articles/java/concurrent/volatile.html" class="sidebar-link">volatile</a></li><li><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html" aria-current="page" class="active sidebar-link">threadLocal</a></li><li><a href="/oliver-vuepress/articles/java/concurrent/reentrantLock.html" class="sidebar-link">reentrantLock</a></li><li><a href="/oliver-vuepress/articles/java/concurrent/synchronized.html" class="sidebar-link">synchronized</a></li><li><a href="/oliver-vuepress/articles/java/concurrent/executor.html" class="sidebar-link">线程池</a></li></ul></section></li></ul> </aside> <div class="password-shadow password-wrapper-in" style="display:none;" data-v-25ba6db2 data-v-130b300a><h3 class="title" data-v-25ba6db2 data-v-25ba6db2>ThreadLocal</h3> <!----> <label id="box" class="inputBox" data-v-25ba6db2 data-v-25ba6db2><input type="password" value="" data-v-25ba6db2> <span data-v-25ba6db2>Konck! Knock!</span> <button data-v-25ba6db2>OK</button></label> <div class="footer" data-v-25ba6db2 data-v-25ba6db2><span data-v-25ba6db2><i class="iconfont reco-theme" data-v-25ba6db2></i> <a target="blank" href="https://vuepress-theme-reco.recoluan.com" data-v-25ba6db2>vuePress-theme-reco</a></span> <span data-v-25ba6db2><i class="iconfont reco-copyright" data-v-25ba6db2></i> <a data-v-25ba6db2><span data-v-25ba6db2>oliver.shi</span>
            
          <!---->
          2022
        </a></span></div></div> <div data-v-130b300a><main class="page"><section><div class="page-title"><h1 class="title">ThreadLocal</h1> <div data-v-f875f3fc><i class="iconfont reco-account" data-v-f875f3fc><span data-v-f875f3fc>oliver.shi</span></i> <i class="iconfont reco-date" data-v-f875f3fc><span data-v-f875f3fc>10/17/2021</span></i> <!----> <i class="tags iconfont reco-tag" data-v-f875f3fc><span class="tag-item" data-v-f875f3fc>Java</span></i></div></div> <div class="theme-reco-content content__default"><h2 id="什么是threadlocal"><a href="#什么是threadlocal" class="header-anchor">#</a> 什么是ThreadLocal</h2> <blockquote><p><code>ThreadLocal</code>   即：线程 的 局部变量，主要是存放每个线程的私有数据<br>
每当你创建一个  <code>ThreadLocal</code>  变量，那么访问这个变量的每个线程都会在当前线程存一份这个变量的本地副本，只有自身线程能够访问，和其他线程是不共享的，这样可以避免线程资源共享变量冲突的问题</p></blockquote> <h2 id="threadlocal的基本使用方式"><a href="#threadlocal的基本使用方式" class="header-anchor">#</a> ThreadLocal的基本使用方式</h2> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ThreadLocalDemoOne</span> <span class="token punctuation">{</span>

    <span class="token comment">/**
     * 创建 ThreadLocal 变量
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> intLocal <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 创建 ThreadLocal 并 初始化赋值
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> intLocal2 <span class="token operator">=</span> <span class="token class-name">ThreadLocal</span><span class="token punctuation">.</span><span class="token function">withInitial</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 设置变量值</span>
        intLocal<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 读取变量值</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;intLocal data: &quot;</span> <span class="token operator">+</span> intLocal<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 清空变量值</span>
        intLocal<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;intLocal data: &quot;</span> <span class="token operator">+</span> intLocal<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;intLocal data: &quot;</span> <span class="token operator">+</span> intLocal2<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

</code></pre></div><h2 id="threadlocal-基本的数据结构"><a href="#threadlocal-基本的数据结构" class="header-anchor">#</a> ThreadLocal  基本的数据结构</h2> <blockquote><p>从 <code>Thread</code> 类源代码入手，可以看到 <code>Thread</code>  中 存有两个  <code>ThreadLocal.ThreadLocalMap</code>  的对象</p></blockquote> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Thread</span> <span class="token keyword">implements</span> <span class="token class-name">Runnable</span> <span class="token punctuation">{</span>
    <span class="token comment">//......</span>
    <span class="token comment">//与此线程有关的ThreadLocal值。由ThreadLocal类维护</span>
    <span class="token class-name">ThreadLocal<span class="token punctuation">.</span>ThreadLocalMap</span> threadLocals <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

    <span class="token comment">//与此线程有关的InheritableThreadLocal值。由InheritableThreadLocal类维护</span>
    <span class="token class-name">ThreadLocal<span class="token punctuation">.</span>ThreadLocalMap</span> inheritableThreadLocals <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token comment">//......</span>
<span class="token punctuation">}</span>
</code></pre></div><p><code>Thread</code>  类中的变量存储变量私有的 ThreadLocal值</p> <ul><li>threadLocals： 线程私有的ThreadLocal 的值</li> <li>inheritableThreadLocals：可以被线程继承的 线程私有的值</li></ul> <p><strong><code>ThreadLocalMap</code></strong></p> <img src="/oliver-vuepress/java/concurrent/threadlocal/1.jpg" alt="foo"> <p><code>ThreadLocalMap</code>  是 ThreadLocal  类实现的定制化的 HashMap</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">ThreadLocalMap</span> <span class="token punctuation">{</span>

    <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">Entry</span> <span class="token keyword">extends</span> <span class="token class-name">WeakReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ThreadLocal</span><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
        <span class="token comment">/** The value associated with this ThreadLocal. */</span>
        <span class="token class-name">Object</span> value<span class="token punctuation">;</span>

        <span class="token class-name">Entry</span><span class="token punctuation">(</span><span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> k<span class="token punctuation">,</span> <span class="token class-name">Object</span> v<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">super</span><span class="token punctuation">(</span>k<span class="token punctuation">)</span><span class="token punctuation">;</span>
            value <span class="token operator">=</span> v<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 初始化空间大小
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> INITIAL_CAPACITY <span class="token operator">=</span> <span class="token number">16</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * The table, resized as necessary.
     * table.length MUST always be a power of two.
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">Entry</span><span class="token punctuation">[</span><span class="token punctuation">]</span> table<span class="token punctuation">;</span>
</code></pre></div><ul><li>key：就是当前线程的 就是 ThreadLocal 对象</li> <li>value:  通过 set 设置的值
<strong><code>注意:</code></strong> <code>Entry extends WeakReference&lt;ThreadLocal&lt;?&gt;&gt;</code>  table 中的 key 是一个 弱引用，这是个值得探讨的点、Java 为何要设计 key 为 弱引用呢？</li></ul> <p><strong><code>总结:</code></strong>  最终的变量是放在了当前线程的 ThreadLocalMap 中，并不是存在 ThreadLocal 上，ThreadLocal 可以理解为只是ThreadLocalMap的封装，传递了变量值。</p> <h2 id="inheritablethreadlocal"><a href="#inheritablethreadlocal" class="header-anchor">#</a> InheritableThreadLocal</h2> <blockquote><p><code>InheritableThreadLocal</code>   主要用于将 主线程的 <code>ThreadLocal</code> 对象, 传递到子线程中</p></blockquote> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">InheritableThreadLocalDemo</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> intLocal<span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">InheritableThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> intInheritableLocal <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InheritableThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>

        intLocal<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        intInheritableLocal<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">Thread</span> thread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> “ ：” <span class="token operator">+</span> intLocal<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> “ ：” <span class="token operator">+</span> intInheritableLocal<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        thread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>执行结果</p> <div class="language- extra-class"><pre class="language-text"><code>Thread-0 ：null
Thread-0 ：2
</code></pre></div><p>可以看到 声明  <code>InheritableThreadLocal</code> 的对象，是能被子线程继承到的。</p> <h2 id="threadlocal-内存泄露问题"><a href="#threadlocal-内存泄露问题" class="header-anchor">#</a> ThreadLocal  内存泄露问题</h2> <p><strong>内存泄露</strong></p> <blockquote><p>程序在申请内存后，无法释放已申请的内存空间，一次内存泄露危害可以忽略，但内存泄露堆积后果很严重，无论多少内存,迟早会被占光</p></blockquote> <p>我看到的很多文章都说，内存泄露 是由于 <code>ThreadLocalMap</code>  的 <code>key</code> 为弱引用导致的，弱引用对象，在没有被外部引用时，当发生GC 是 key 被回收为 null, 但是 value 还存在强引用，可能会存在 内存泄露问题</p> <p>但其实，由于 Thread -&gt; ThreadLocalMap -&gt; Entry -&gt; value 存在这样一条引用链<br>
只要 <code>Thread</code> 不被退出，<code>ThreadLocalMap</code> 的生命周期将是一样长的，如果不进行手动删除，必然会出现内存泄露。更何况我们大多数是以线程池的方式去操作线程。</p> <blockquote><p>那又是如果解决的内存泄露 ?</p></blockquote> <p><code>ThreadLocal</code> 设置了两层保障:</p> <ul><li>key :  创建为弱引用对象</li> <li>调用 <code>set()</code>, <code>get()</code>, <code>remove()</code>   都会对 key = null 进行清除 value 操作</li></ul> <p><strong><code>总结:</code></strong><br> <code>threadLocal</code> 内存泄漏的根源是：由于 <code>ThreadLocalMap</code> 的生命周期跟 <code>Thread</code>一样长，如果没有手动删除对应 <code>key</code> 就会导致内存泄漏，而不是因为弱引用。</p> <p><strong>建议：在使用ThreadLocal的时候要养成及时 <code>remove()</code>的习惯</strong></p> <h3 id="源码中分析防止内存泄露的-清除操作"><a href="#源码中分析防止内存泄露的-清除操作" class="header-anchor">#</a> 源码中分析防止内存泄露的 清除操作</h3> <p><code>ThreadLocal</code>  中有两种清除方式:</p> <ul><li>expungeStaleEntry()  探测式清理</li> <li>cleanSomeSlots() 启发式清除</li></ul> <p><strong><code>remove() 源码:</code></strong></p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 获取当前线程绑定的 threadLocals</span>
    <span class="token class-name">ThreadLocalMap</span> m <span class="token operator">=</span> <span class="token function">getMap</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 当 map 不为 null 进行移除当前线程中指点的 ThreadLocal 对象的 值</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>m <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
        m<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">remove</span><span class="token punctuation">(</span><span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Entry</span><span class="token punctuation">[</span><span class="token punctuation">]</span> tab <span class="token operator">=</span> table<span class="token punctuation">;</span>
    <span class="token keyword">int</span> len <span class="token operator">=</span> tab<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
    <span class="token comment">// 计算 ThreadLocal key 的下标值</span>
    <span class="token keyword">int</span> i <span class="token operator">=</span> key<span class="token punctuation">.</span>threadLocalHashCode <span class="token operator">&amp;</span> <span class="token punctuation">(</span>len<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 循环遍历 只要不为null</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Entry</span> e <span class="token operator">=</span> tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
         e <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
         e <span class="token operator">=</span> tab<span class="token punctuation">[</span>i <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 比对 key 值，如果相等的话</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 调用 clear() 方法清理掉</span>
            e<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 执行 探测式清理  将 key 为 null 的节点 进行清除</span>
            <span class="token function">expungeStaleEntry</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>


<span class="token keyword">private</span> <span class="token keyword">int</span> <span class="token function">expungeStaleEntry</span><span class="token punctuation">(</span><span class="token keyword">int</span> staleSlot<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Entry</span><span class="token punctuation">[</span><span class="token punctuation">]</span> tab <span class="token operator">=</span> table<span class="token punctuation">;</span>
    <span class="token keyword">int</span> len <span class="token operator">=</span> tab<span class="token punctuation">.</span>length<span class="token punctuation">;</span>

    <span class="token comment">// expunge entry at staleSlot</span>
    tab<span class="token punctuation">[</span>staleSlot<span class="token punctuation">]</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    tab<span class="token punctuation">[</span>staleSlot<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    size<span class="token operator">--</span><span class="token punctuation">;</span>

    <span class="token comment">// Rehash until we encounter null</span>
    <span class="token class-name">Entry</span> e<span class="token punctuation">;</span>
    <span class="token keyword">int</span> i<span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>staleSlot<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
         <span class="token punctuation">(</span>e <span class="token operator">=</span> tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
         i <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> k <span class="token operator">=</span> e<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//对table中key为null进行处理,将value设置为null，清除value的引用</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
            tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
            size<span class="token operator">--</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token keyword">int</span> h <span class="token operator">=</span> k<span class="token punctuation">.</span>threadLocalHashCode <span class="token operator">&amp;</span> <span class="token punctuation">(</span>len <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>h <span class="token operator">!=</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
                <span class="token comment">//这里主要的作用是由于采用了开放地址法，所以删除的元素是多个冲突元素中的一个，需要对后面的元素作</span>
                <span class="token comment">//处理，可以简单理解就是让后面的元素往前面移动</span>
                <span class="token comment">// Unlike Knuth 6.4 Algorithm R, we must scan until</span>
                <span class="token comment">// null because multiple entries could have been stale.</span>
                <span class="token keyword">while</span> <span class="token punctuation">(</span>tab<span class="token punctuation">[</span>h<span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
                    h <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>h<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
                tab<span class="token punctuation">[</span>h<span class="token punctuation">]</span> <span class="token operator">=</span> e<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><img src="/oliver-vuepress/java/concurrent/threadlocal/2.jpg" alt="foo"> <p><strong><code>get() 源码:</code></strong></p> <div class="language-java extra-class"><pre class="language-java"><code>
<span class="token keyword">public</span> <span class="token class-name">T</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 获取当前线程绑定的 threadLocals</span>
    <span class="token class-name">Thread</span> t <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">ThreadLocalMap</span> map <span class="token operator">=</span> <span class="token function">getMap</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 当 map 不为 null</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>map <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 查询当前ThreadLocal变量实例对应的Entry  (获取中内部调用了清除)</span>
        <span class="token class-name">ThreadLocalMap<span class="token punctuation">.</span>Entry</span> e <span class="token operator">=</span> map<span class="token punctuation">.</span><span class="token function">getEntry</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 如果不为null,获取value,返回</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>e <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token annotation punctuation">@SuppressWarnings</span><span class="token punctuation">(</span><span class="token string">&quot;unchecked&quot;</span><span class="token punctuation">)</span>
            <span class="token class-name">T</span> result <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">)</span> e<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
            <span class="token keyword">return</span> result<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 当 map 为 null 进行初始化</span>
    <span class="token keyword">return</span> <span class="token function">setInitialValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token class-name">Entry</span> <span class="token function">getEntry</span><span class="token punctuation">(</span><span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> i <span class="token operator">=</span> key<span class="token punctuation">.</span>threadLocalHashCode <span class="token operator">&amp;</span> <span class="token punctuation">(</span>table<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Entry</span> e <span class="token operator">=</span> table<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token comment">// 对应的entry存在且 ThreadLocal就是key，则命中返回</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>e <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> e<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> key<span class="token punctuation">)</span>
        <span class="token keyword">return</span> e<span class="token punctuation">;</span>
    <span class="token keyword">else</span>
        <span class="token comment">// 如果不是 则进行线性探针，往后进行查找元素</span>
        <span class="token keyword">return</span> <span class="token function">getEntryAfterMiss</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> i<span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token keyword">private</span> <span class="token class-name">Entry</span> <span class="token function">getEntryAfterMiss</span><span class="token punctuation">(</span><span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> key<span class="token punctuation">,</span> <span class="token keyword">int</span> i<span class="token punctuation">,</span> <span class="token class-name">Entry</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Entry</span><span class="token punctuation">[</span><span class="token punctuation">]</span> tab <span class="token operator">=</span> table<span class="token punctuation">;</span>
    <span class="token keyword">int</span> len <span class="token operator">=</span> tab<span class="token punctuation">.</span>length<span class="token punctuation">;</span>

    <span class="token keyword">while</span> <span class="token punctuation">(</span>e <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> k <span class="token operator">=</span> e<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 该 entry 当前的 ThreadLocal 返回数据</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>k <span class="token operator">==</span> key<span class="token punctuation">)</span>
            <span class="token keyword">return</span> e<span class="token punctuation">;</span>
        <span class="token comment">// 该 entry 对应的 ThreadLocal 已经被回收 进行 探测式清除</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
            <span class="token function">expungeStaleEntry</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">else</span>
            <span class="token comment">// 指向下个 槽位 往下循环</span>
            i <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
        e <span class="token operator">=</span> tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

</code></pre></div><img src="/oliver-vuepress/java/concurrent/threadlocal/3.jpg" alt="foo"> <p><strong><code>set() 源码:</code></strong></p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> key<span class="token punctuation">,</span> <span class="token class-name">Object</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//.... 省略部分代码 </span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Entry</span> e <span class="token operator">=</span> tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
		   <span class="token comment">//.... 省略部分代码 </span>
        <span class="token comment">// 冲突位 key 为 null 则说明  被 GC 回收，进行清理回收数据</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 清理 key 被 GC 为null的数据  replaceStaleEntry 内部进行探针式清除</span>
            <span class="token function">replaceStaleEntry</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token comment">//.... 省略部分代码 </span>
    <span class="token comment">// 检查是否需要进行扩容   cleanSomeSlots(i, sz) 启发式清除</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">cleanSomeSlots</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> sz<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> sz <span class="token operator">&gt;=</span> threshold<span class="token punctuation">)</span>
        <span class="token function">rehash</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

</code></pre></div><blockquote><p>通过  <code>set()</code>, <code>get()</code>, <code>remove()</code>  三个方法的源码调用查看，可以明确的知道 <code>ThreadLocal</code>  做了很多清除操作，为了防止 内存泄露</p></blockquote> <h3 id="具体的清除流程"><a href="#具体的清除流程" class="header-anchor">#</a> 具体的清除流程</h3> <blockquote><p>expungeStaleEntry： 是对 ThreadLocal 被回收的节点开始，向后进行查找时候还存在被回收的节点进行清除操作</p></blockquote> <div class="language-java extra-class"><pre class="language-java"><code>
<span class="token comment">/**
 * 探测式清除
 * @param staleSlot 为null 的 节点位置
 * @return
 */</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> <span class="token function">expungeStaleEntry</span><span class="token punctuation">(</span><span class="token keyword">int</span> staleSlot<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Entry</span><span class="token punctuation">[</span><span class="token punctuation">]</span> tab <span class="token operator">=</span> table<span class="token punctuation">;</span>
    <span class="token keyword">int</span> len <span class="token operator">=</span> tab<span class="token punctuation">.</span>length<span class="token punctuation">;</span>

    <span class="token comment">// expunge entry at staleSlot</span>
    tab<span class="token punctuation">[</span>staleSlot<span class="token punctuation">]</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    tab<span class="token punctuation">[</span>staleSlot<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    size<span class="token operator">--</span><span class="token punctuation">;</span>

    <span class="token comment">// Rehash until we encounter null</span>
    <span class="token class-name">Entry</span> e<span class="token punctuation">;</span>
    <span class="token keyword">int</span> i<span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>staleSlot<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
         <span class="token punctuation">(</span>e <span class="token operator">=</span> tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
         i <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> k <span class="token operator">=</span> e<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//对table中key为null进行处理,将value设置为null，清除value的引用</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
            tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
            size<span class="token operator">--</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token keyword">int</span> h <span class="token operator">=</span> k<span class="token punctuation">.</span>threadLocalHashCode <span class="token operator">&amp;</span> <span class="token punctuation">(</span>len <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>h <span class="token operator">!=</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
                <span class="token comment">//这里主要的作用是由于采用了开放地址法，所以删除的元素是多个冲突元素中的一个，需要对后面的元素作</span>
                <span class="token comment">//处理，可以简单理解就是让后面的元素往前面移动</span>
                <span class="token comment">// Unlike Knuth 6.4 Algorithm R, we must scan until</span>
                <span class="token comment">// null because multiple entries could have been stale.</span>
                <span class="token keyword">while</span> <span class="token punctuation">(</span>tab<span class="token punctuation">[</span>h<span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
                    h <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>h<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
                tab<span class="token punctuation">[</span>h<span class="token punctuation">]</span> <span class="token operator">=</span> e<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><ul><li>cleanSomeSlots： 是从指定节点位置，通过n 来控制查找的次数，进行多次清除操作
<ul><li>expungeStaleEntry 返回了下一个为空的节点位置</li> <li>cleanSomeSlots 会从 下一个为空节点位置，再次进行扫描操作</li> <li>具体能进行几次扫描 ，第一次是 传递来的 n , 从第二次开始 是 table 的 长度来决定的</li></ul></li></ul> <div class="language- extra-class"><pre class="language-text"><code>

/**
 * 启发式清除
 * @param i 当前的节点位置
 * @param n 是用于控制控制扫描次数的
 * @return
 */
private boolean cleanSomeSlots(int i, int n) {
    boolean removed = false;
    Entry[] tab = table;
    int len = tab.length;
    do {
        i = nextIndex(i, len);
        Entry e = tab[i];
        if (e != null &amp;&amp; e.get() == null) {
            // 扩大扫描控制因子 设置成表的长度
            n = len;
            removed = true;
            // 使用 探测式清除 进行清除操作
            i = expungeStaleEntry(i);
        }
    } while ((n &gt;&gt;&gt;= 1) != 0);
    return removed;
}
</code></pre></div><p><strong><code>总结:</code></strong>  可以看到  <code>cleanSomeSlots</code>  底层 还是通过  <code>expungeStaleEntry</code>  去进行清除的。但是  <code>cleanSomeSlots</code>  清除范围 要比  <code>expungeStaleEntry</code>   大</p> <h2 id="threadlocalmap-的hash冲突"><a href="#threadlocalmap-的hash冲突" class="header-anchor">#</a> ThreadLocalMap 的Hash冲突</h2> <blockquote><p><code>ThreadLocal</code>  底层 没有 <code>java.util.HashMap</code> 作为底层的Map 数据结构 所以需要使用不同的 Hash冲突解决方案
<code>java.util.HashMap</code>  使用  数组 + 链表 （链表一定长度转化为红黑树）的方式解决 Hash 冲突问题
<code>ThreadLocalMap</code>  则是使用 线性探测法</p></blockquote> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> key<span class="token punctuation">,</span> <span class="token class-name">Object</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Entry</span><span class="token punctuation">[</span><span class="token punctuation">]</span> tab <span class="token operator">=</span> table<span class="token punctuation">;</span>
    <span class="token keyword">int</span> len <span class="token operator">=</span> tab<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
    <span class="token comment">// 根据 hash 找到 map 中的下标</span>
    <span class="token keyword">int</span> i <span class="token operator">=</span> key<span class="token punctuation">.</span>threadLocalHashCode <span class="token operator">&amp;</span> <span class="token punctuation">(</span>len<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 进行 线性探测 如果有冲突 则 进循环体内进行操作</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Entry</span> e <span class="token operator">=</span> tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
         e <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
         e <span class="token operator">=</span> tab<span class="token punctuation">[</span>i <span class="token operator">=</span> <span class="token function">nextIndex</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> k <span class="token operator">=</span> e<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 冲突位置的 key 就是自身时，直接赋值</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>k <span class="token operator">==</span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 冲突位 key 为 null 则说明  被 GC 回收，进行清理回收数据</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 清理 key 被 GC 为null的数据</span>
            <span class="token function">replaceStaleEntry</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 找到可利用的桶位 赋值</span>
    tab<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Entry</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> sz <span class="token operator">=</span> <span class="token operator">++</span>size<span class="token punctuation">;</span>
    <span class="token comment">// 检查是否需要进行扩容</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">cleanSomeSlots</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> sz<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> sz <span class="token operator">&gt;=</span> threshold<span class="token punctuation">)</span>
        <span class="token function">rehash</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="threadlocalmap-的扩容机制"><a href="#threadlocalmap-的扩容机制" class="header-anchor">#</a> ThreadLocalMap 的扩容机制</h2> <p>相关扩容参数:</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token comment">/**
 * 初始化容量条数
 */</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> INITIAL_CAPACITY <span class="token operator">=</span> <span class="token number">16</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * The table, resized as necessary.
 * table.length MUST always be a power of two.
 */</span>
<span class="token keyword">private</span> <span class="token class-name">Entry</span><span class="token punctuation">[</span><span class="token punctuation">]</span> table<span class="token punctuation">;</span>

<span class="token comment">/**
 * 当前表中的条数
 */</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> size <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * 表 扩容的 下次扩容阀值
 */</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> threshold<span class="token punctuation">;</span> <span class="token comment">// Default to 0</span>

<span class="token comment">/**
 * 设定扩容阈值公式
 */</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">setThreshold</span><span class="token punctuation">(</span><span class="token keyword">int</span> len<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    threshold <span class="token operator">=</span> len <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">/</span> <span class="token number">3</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>具体的 <code>set()</code>  方法</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> key<span class="token punctuation">,</span> <span class="token class-name">Object</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token comment">//..... 上面代码省略</span>
      <span class="token comment">// 检查是否需要进行扩容</span>
      <span class="token comment">// 条件： 当 启发式清除操作 没有清除到数据时 &amp;&amp; 表中条数 &gt;= 当前设置的扩容阀值</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">cleanSomeSlots</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> sz<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> sz <span class="token operator">&gt;=</span> threshold<span class="token punctuation">)</span>
        <span class="token function">rehash</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>从基本的参数 、扩容 参数 、以及 set() 中的 扩容判断  我们知道 基本的扩容判断</p> <ul><li>启发式清除操作 没有清除到数据时</li> <li>当前 表中元素个数 &gt;= threshold (16 * 2/ 3 = 10.6)</li></ul> <p><strong><code>但真的是这样吗？</code></strong> 接着查看  <code>rehash()</code>  方法</p> <div class="language-java extra-class"><pre class="language-java"><code>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">rehash</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 先进行探针式 清除 GC 元素</span>
    <span class="token function">expungeStaleEntries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// Use lower threshold for doubling to avoid hysteresis</span>
    
    <span class="token comment">// 清除 后的 表中个数 大于  下次 扩容阀值 75% ~ 80%进行 扩容</span>
    <span class="token comment">// 是以 第一次扩容的值来算的 具体对不对 不是很确定</span>
    <span class="token comment">// 初始： threshold =  threshold = len * 2 / 3;  16 * 2/ 3 = 10.6  </span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>size <span class="token operator">&gt;=</span> threshold <span class="token operator">-</span> threshold <span class="token operator">/</span> <span class="token number">4</span><span class="token punctuation">)</span>
        <span class="token function">resize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

</code></pre></div><p><strong><code>总结:</code></strong><br> <code>ThreadLocalMap</code>  的扩容操作，进行了2次 <code>Null</code>  key 元素的清除，并在每次清除后进行 阀值计算。个人理解这样的操作的原因，主要还是由于扩容时，需要进行元素位置的移动操作，为了减少移动操作。<br> <strong><code>注:</code></strong>  元素位移时 会再一次  对 <code>Null</code>  key 元素的进行清除操作</p> <img src="/oliver-vuepress/java/concurrent/threadlocal/4.jpg" alt="foo"> <p>【相关资料】</p> <ul><li><a href="https://zhuanlan.zhihu.com/p/102571059" target="_blank" rel="noopener noreferrer">ThreadLocal的内存泄露？什么原因？如何避免？ - 知乎<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></section> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新: </span> <span class="time">4/21/2022, 8:17:59 AM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev"><a href="/oliver-vuepress/articles/java/concurrent/volatile.html" class="prev">
            volatile
          </a></span> <span class="next"><a href="/oliver-vuepress/articles/java/concurrent/reentrantLock.html">
            reentrantLock
          </a></span></p></div> <div class="comments-wrapper"><!----></div> <ul class="side-bar sub-sidebar-wrapper" style="width:12rem;" data-v-cb1513f6><li class="level-2" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#什么是threadlocal" class="sidebar-link reco-side-什么是threadlocal" data-v-cb1513f6>什么是ThreadLocal</a></li><li class="level-2" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#threadlocal的基本使用方式" class="sidebar-link reco-side-threadlocal的基本使用方式" data-v-cb1513f6>ThreadLocal的基本使用方式</a></li><li class="level-2" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#threadlocal-基本的数据结构" class="sidebar-link reco-side-threadlocal-基本的数据结构" data-v-cb1513f6>ThreadLocal  基本的数据结构</a></li><li class="level-2" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#inheritablethreadlocal" class="sidebar-link reco-side-inheritablethreadlocal" data-v-cb1513f6>InheritableThreadLocal</a></li><li class="level-2" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#threadlocal-内存泄露问题" class="sidebar-link reco-side-threadlocal-内存泄露问题" data-v-cb1513f6>ThreadLocal  内存泄露问题</a></li><li class="level-3" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#源码中分析防止内存泄露的-清除操作" class="sidebar-link reco-side-源码中分析防止内存泄露的-清除操作" data-v-cb1513f6>源码中分析防止内存泄露的 清除操作</a></li><li class="level-3" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#具体的清除流程" class="sidebar-link reco-side-具体的清除流程" data-v-cb1513f6>具体的清除流程</a></li><li class="level-2" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#threadlocalmap-的hash冲突" class="sidebar-link reco-side-threadlocalmap-的hash冲突" data-v-cb1513f6>ThreadLocalMap 的Hash冲突</a></li><li class="level-2" data-v-cb1513f6><a href="/oliver-vuepress/articles/java/concurrent/threadlocal.html#threadlocalmap-的扩容机制" class="sidebar-link reco-side-threadlocalmap-的扩容机制" data-v-cb1513f6>ThreadLocalMap 的扩容机制</a></li></ul></main> <!----></div></div></div></div><div class="global-ui"><div class="back-to-ceiling" style="right:1rem;bottom:6rem;width:2.5rem;height:2.5rem;border-radius:.25rem;line-height:2.5rem;display:none;" data-v-c6073ba8 data-v-c6073ba8><svg t="1574745035067" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5404" class="icon" data-v-c6073ba8><path d="M526.60727968 10.90185116a27.675 27.675 0 0 0-29.21455937 0c-131.36607665 82.28402758-218.69155461 228.01873535-218.69155402 394.07834331a462.20625001 462.20625001 0 0 0 5.36959153 69.94390903c1.00431239 6.55289093-0.34802892 13.13561351-3.76865779 18.80351572-32.63518765 54.11355614-51.75690182 118.55860487-51.7569018 187.94566865a371.06718723 371.06718723 0 0 0 11.50484808 91.98906777c6.53300375 25.50556257 41.68394495 28.14064038 52.69160883 4.22606766 17.37162448-37.73630017 42.14135425-72.50938081 72.80769204-103.21549295 2.18761121 3.04276886 4.15646224 6.24463696 6.40373557 9.22774369a1871.4375 1871.4375 0 0 0 140.04691725 5.34970492 1866.36093723 1866.36093723 0 0 0 140.04691723-5.34970492c2.24727335-2.98310674 4.21612437-6.18497483 6.3937923-9.2178004 30.66633723 30.70611158 55.4360664 65.4791928 72.80769147 103.21549355 11.00766384 23.91457269 46.15860503 21.27949489 52.69160879-4.22606768a371.15156223 371.15156223 0 0 0 11.514792-91.99901164c0-69.36717486-19.13165746-133.82216804-51.75690182-187.92578088-3.42062944-5.66790279-4.76302748-12.26056868-3.76865837-18.80351632a462.20625001 462.20625001 0 0 0 5.36959269-69.943909c-0.00994388-166.08943902-87.32547796-311.81420293-218.6915546-394.09823051zM605.93803103 357.87693858a93.93749974 93.93749974 0 1 1-187.89594924 6.1e-7 93.93749974 93.93749974 0 0 1 187.89594924-6.1e-7z" p-id="5405" data-v-c6073ba8></path><path d="M429.50777625 765.63860547C429.50777625 803.39355007 466.44236686 1000.39046097 512.00932183 1000.39046097c45.56695499 0 82.4922232-197.00623328 82.5015456-234.7518555 0-37.75494459-36.9345906-68.35043303-82.4922232-68.34111062-45.57627738-0.00932239-82.52019037 30.59548842-82.51086798 68.34111062z" p-id="5406" data-v-c6073ba8></path></svg></div></div></div>
    <script src="/oliver-vuepress/assets/js/app.c21e6ffc.js" defer></script><script src="/oliver-vuepress/assets/js/3.6dd9a2a1.js" defer></script><script src="/oliver-vuepress/assets/js/1.898920d0.js" defer></script><script src="/oliver-vuepress/assets/js/29.50398f0f.js" defer></script>
  </body>
</html>
